package com.google.jessewilson.codesearch.standalone;

import com.google.jessewilson.codesearch.api.CodeFile;
import com.google.jessewilson.codesearch.api.Line;
import com.google.jessewilson.codesearch.api.QueryResponse;
import com.google.jessewilson.codesearch.api.spi.SearchProviderBackend;
import com.google.jessewilson.codesearch.io.FileDownloader;
import com.google.jessewilson.codesearch.ui.Documents;
import com.google.jessewilson.codesearch.util.Progress;
import com.google.jessewilson.codesearch.util.Throwables;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;

import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

/**
 * Display a selected file in a Frame.
 *
 * @author jessewilson
 */
public class FileInFrameViewer {

  private final ExecutorService executorService;
  private final FileDownloader fileDownloader;

  private JFrame frame;
  private JTextPane textPane;


  public FileInFrameViewer(ExecutorService executorService,
      SearchProviderBackend searchProviderBackend) {
    this.executorService = executorService;
    this.fileDownloader = new FileDownloader(searchProviderBackend);

    this.textPane = new JTextPane();
    JScrollPane scrollPane = new JScrollPane(textPane,
        JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
        JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    this.frame = new JFrame();
    this.frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    this.frame.setSize(640, 400);
    this.frame.setLocationRelativeTo(null);
    this.frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
  }


  public void open(final CodeFile codeFile, final Line line, QueryResponse results) {
    // notify what we're doing on the EDT
    textPane.setText("Downloading " + codeFile.getPath().toString());

    // download off the EDT
    final Progress.Task task = results.getProgress().startTask();
    executorService.submit(new Runnable() {
      public void run() {
        final FileDownloader.Result result = fileDownloader.download(codeFile);

        // display on the EDT
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            if(result.isSuccess()) {
              reloadLocalFile(result.getLocalFile());
              if(line != null) {
                scrollToLine(line);
              }
            } else {
              displayError(result.getException());
            }

            task.finished();
          }
        });
      }
    });
  }


  private void scrollToLine(Line line) {
    Document document = textPane.getDocument();

    // found a matching reference in the document.
    try {
      int lineStart = Documents.characterAtLine(document, line.getLineNumber());
      int lineEnd = Documents.characterAtLine(document, line.getLineNumber() + 1);

      if(lineStart > 0 && lineEnd > 0) {
        textPane.select(lineStart, lineEnd);
      } else if(lineStart > 0) {
        textPane.select(lineStart, document.getLength());
      }


    } catch (BadLocationException e) {
      throw new RuntimeException(e);
    }
  }

  private void displayError(Throwable t) {
    textPane.setText(Throwables.stackTraceToString(t));
  }

  private void reloadLocalFile(File localFile) {
    try {
      textPane.setPage(localFile.toURL());
    } catch (IOException e) {
      displayError(e);
    }
  }

  public void setVisible(boolean visible) {
    frame.setVisible(visible);
  }
}
